package asteroids.model.statements;

import java.util.*;

import asteroids.model.Ship;
import asteroids.model.expressions.*;
import asteroids.model.types.T;

/**
 * A class that represents an if-else statement
 * 
 * @version 1.0
 * 
 * @author	Thijs Peirelinck & Wouter Parys
 *
 */
public class IfElse extends ExpressionStatement implements NormalS {
	
	private S ifS;
	private S elseS;
	
	public IfElse(E e, S s1, S s2) {
		super(e);
		this.ifS = s1;
		this.elseS = s2;
	}
	
	@Override
	public void setExecuter(Ship executer) {
		ifS.setExecuter(executer);
		elseS.setExecuter(executer);
		getExpression().setExecuter(executer);
	}
	
	public boolean isValidCondition() {
		return getExpression().getReturnType().equals("boolean");
	}

	@Override
	public Iterator<S> iterator(final HashMap<String, E> variables) {
		return new Iterator<S>() {
			
			private Iterator<S> currentIterator;
			private E conditionInIt;

			@Override
			public boolean hasNext() {
				if(currentIterator != null) {
					return currentIterator.hasNext();
				}
				else {
					conditionInIt = getValidatedExpressionCopy(getExpression(), variables);
					if((Boolean)conditionInIt.getValue()) {
						return ((NormalS)ifS).iterator(variables).hasNext();
					}
					else {
						return ((NormalS)elseS).iterator(variables).hasNext();
					}
				}
				
			}

			@Override
			public S next() throws NoSuchElementException {
				if(!hasNext())
					throw new NoSuchElementException();
				if(currentIterator != null) {
					if(currentIterator.hasNext())
						return currentIterator.next();
				}
				else {
					conditionInIt = getValidatedExpressionCopy(getExpression(), variables);
					if((Boolean)conditionInIt.getValue()) {
						currentIterator = ((NormalS)ifS).iterator(variables);
					}
					else {
						currentIterator = ((NormalS)elseS).iterator(variables);
					}
				}
				conditionInIt = getValidatedExpressionCopy(getExpression(), variables);
				return currentIterator.next();	
			}

			@Override
			public void remove() throws UnsupportedOperationException {
				throw new UnsupportedOperationException();
			}
			
		};
	}

	@Override
	public boolean typeCheck(Map<String, T> globals) {
		boolean ifs = ifS.typeCheck(globals);
		boolean elses = elseS.typeCheck(globals);
		if(getExpression() instanceof Variable) {
			if(globals.get(getExpression().getValue()) == null) 
				return false;
			else
				return globals.get(getExpression().getValue()).getReturnType().equals("boolean") && ifs && elses;
		}
		else
			return (getExpression().typeCheck(globals)) && (getExpression().getReturnType().equals("boolean")) && ifs && elses;
	}
	
	@Override
	public boolean containsAction() {
		return ((NormalS)ifS).containsAction() && ((NormalS)elseS).containsAction();
	}
	
}